home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / EXAMPLES / ZOOMDINO.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  12.4 KB  |  465 lines

  1.  
  2. /* Copyright (c) Mark J. Kilgard, 1994.  */
  3.  
  4. /* This program is freely distributable without licensing fees 
  5.    and is provided without guarantee or warrantee expressed or 
  6.    implied. This program is -not- in the public domain. */
  7.  
  8. /* zoomdino demonstrates GLUT 3.0's new overlay support.  Both
  9.    rubber-banding the display of a help message use the overlays. */
  10.  
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <math.h>       /* for cos(), sin(), and sqrt() */
  15. #include <GL/glut.h>
  16.  
  17. typedef enum {
  18.   RESERVED, BODY_SIDE, BODY_EDGE, BODY_WHOLE, ARM_SIDE, ARM_EDGE, ARM_WHOLE,
  19.   LEG_SIDE, LEG_EDGE, LEG_WHOLE, EYE_SIDE, EYE_EDGE, EYE_WHOLE, DINOSAUR
  20. } displayLists;
  21.  
  22. GLfloat angle = -150;   /* in degrees */
  23. int moving, begin;
  24. int W = 300, H = 300;
  25. GLdouble bodyWidth = 3.0;
  26. int newModel = 1;
  27. /* *INDENT-OFF* */
  28. GLfloat body[][2] = { {0, 3}, {1, 1}, {5, 1}, {8, 4}, {10, 4}, {11, 5},
  29.   {11, 11.5}, {13, 12}, {13, 13}, {10, 13.5}, {13, 14}, {13, 15}, {11, 16},
  30.   {8, 16}, {7, 15}, {7, 13}, {8, 12}, {7, 11}, {6, 6}, {4, 3}, {3, 2},
  31.   {1, 2} };
  32. GLfloat arm[][2] = { {8, 10}, {9, 9}, {10, 9}, {13, 8}, {14, 9}, {16, 9},
  33.   {15, 9.5}, {16, 10}, {15, 10}, {15.5, 11}, {14.5, 10}, {14, 11}, {14, 10},
  34.   {13, 9}, {11, 11}, {9, 11} };
  35. GLfloat leg[][2] = { {8, 6}, {8, 4}, {9, 3}, {9, 2}, {8, 1}, {8, 0.5}, {9, 0},
  36.   {12, 0}, {10, 1}, {10, 2}, {12, 4}, {11, 6}, {10, 7}, {9, 7} };
  37. GLfloat eye[][2] = { {8.75, 15}, {9, 14.7}, {9.6, 14.7}, {10.1, 15},
  38.   {9.6, 15.25}, {9, 15.25} };
  39. GLfloat lightZeroPosition[] = {10.0, 4.0, 10.0, 1.0};
  40. GLfloat lightZeroColor[] = {0.8, 1.0, 0.8, 1.0}; /* green-tinted */
  41. GLfloat lightOnePosition[] = {-1.0, -2.0, 1.0, 0.0};
  42. GLfloat lightOneColor[] = {0.6, 0.3, 0.2, 1.0}; /* red-tinted */
  43. GLfloat skinColor[] = {0.1, 1.0, 0.1, 1.0}, eyeColor[] = {1.0, 0.2, 0.2, 1.0};
  44. int overlaySupport, red, white, transparent, rubberbanding;
  45. int anchorx, anchory, stretchx, stretchy, pstretchx, pstretchy;
  46. float vx, vy, vx2, vy2, vw, vh;
  47. float wx, wy, wx2, wy2, ww, wh;
  48. int fancy, wasFancy, help, clearHelp;
  49. /* *INDENT-ON* */
  50.  
  51. void
  52. extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
  53.   GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
  54. {
  55.   static GLUtriangulatorObj *tobj = NULL;
  56.   GLdouble vertex[3], dx, dy, len;
  57.   int i;
  58.   int count = dataSize / (int) (2 * sizeof(GLfloat));
  59.  
  60.   if (tobj == NULL) {
  61.     tobj = gluNewTess();  /* create and initialize a GLU
  62.                              polygontesselation object */
  63.     gluTessCallback(tobj, GLU_BEGIN, glBegin);
  64.     gluTessCallback(tobj, GLU_VERTEX, glVertex2fv);  /* semi-tricky 
  65.  
  66.                                                       */
  67.     gluTessCallback(tobj, GLU_END, glEnd);
  68.   }
  69.   glNewList(side, GL_COMPILE);
  70.   glShadeModel(GL_SMOOTH);  /* smooth minimizes seeing
  71.                                tessellation */
  72.   gluBeginPolygon(tobj);
  73.   for (i = 0; i < count; i++) {
  74.     vertex[0] = data[i][0];
  75.     vertex[1] = data[i][1];
  76.     vertex[2] = 0;
  77.     gluTessVertex(tobj, vertex, data[i]);
  78.   }
  79.   gluEndPolygon(tobj);
  80.   glEndList();
  81.   glNewList(edge, GL_COMPILE);
  82.   glShadeModel(GL_FLAT);  /* flat shade keeps angular hands
  83.                              from being "smoothed" */
  84.   glBegin(GL_QUAD_STRIP);
  85.   for (i = 0; i <= count; i++) {
  86.     /* mod function handles closing the edge */
  87.     glVertex3f(data[i % count][0], data[i % count][1], 0.0);
  88.     glVertex3f(data[i % count][0], data[i % count][1], thickness);
  89.  
  90.     /* Calculate a unit normal by dividing by Euclidean
  91.        distance. We could be lazy and use
  92.        glEnable(GL_NORMALIZE) so we could pass in arbitrary
  93.        normals for a very slight performance hit. */
  94.  
  95.     dx = data[(i + 1) % count][1] - data[i % count][1];
  96.     dy = data[i % count][0] - data[(i + 1) % count][0];
  97.     len = sqrt(dx * dx + dy * dy);
  98.     glNormal3f(dx / len, dy / len, 0.0);
  99.   }
  100.   glEnd();
  101.   glEndList();
  102.   glNewList(whole, GL_COMPILE);
  103.   glFrontFace(GL_CW);
  104.   glCallList(edge);
  105.   glNormal3f(0.0, 0.0, -1.0);  /* constant normal for side */
  106.   glCallList(side);
  107.   glPushMatrix();
  108.   glTranslatef(0.0, 0.0, thickness);
  109.   glFrontFace(GL_CCW);
  110.   glNormal3f(0.0, 0.0, 1.0);  /* opposite normal for other side */
  111.   glCallList(side);
  112.   glPopMatrix();
  113.   glEndList();
  114. }
  115.  
  116. void
  117. makeDinosaur(void)
  118. {
  119.   extrudeSolidFromPolygon(body, sizeof(body), bodyWidth,
  120.     BODY_SIDE, BODY_EDGE, BODY_WHOLE);
  121.   extrudeSolidFromPolygon(arm, sizeof(arm), bodyWidth / 4,
  122.     ARM_SIDE, ARM_EDGE, ARM_WHOLE);
  123.   extrudeSolidFromPolygon(leg, sizeof(leg), bodyWidth / 2,
  124.     LEG_SIDE, LEG_EDGE, LEG_WHOLE);
  125.   extrudeSolidFromPolygon(eye, sizeof(eye), bodyWidth + 0.2,
  126.     EYE_SIDE, EYE_EDGE, EYE_WHOLE);
  127.   glNewList(DINOSAUR, GL_COMPILE);
  128.   glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
  129.   glCallList(BODY_WHOLE);
  130.   glPushMatrix();
  131.   glTranslatef(0.0, 0.0, bodyWidth);
  132.   glCallList(ARM_WHOLE);
  133.   glCallList(LEG_WHOLE);
  134.   glTranslatef(0.0, 0.0, -bodyWidth - bodyWidth / 4);
  135.   glCallList(ARM_WHOLE);
  136.   glTranslatef(0.0, 0.0, -bodyWidth / 4);
  137.   glCallList(LEG_WHOLE);
  138.   glTranslatef(0.0, 0.0, bodyWidth / 2 - 0.1);
  139.   glMaterialfv(GL_FRONT, GL_DIFFUSE, eyeColor);
  140.   glCallList(EYE_WHOLE);
  141.   glPopMatrix();
  142.   glEndList();
  143. }
  144.  
  145. void
  146. recalcModelView(void)
  147. {
  148.   glPopMatrix();
  149.   glPushMatrix();
  150.   glRotatef(angle, 0.0, 1.0, 0.0);
  151.   glTranslatef(-8, -8, -bodyWidth / 2);
  152.   newModel = 0;
  153. }
  154.  
  155. void
  156. redraw(void)
  157. {
  158.   if (newModel)
  159.     recalcModelView();
  160.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  161.   glCallList(DINOSAUR);
  162.   glutSwapBuffers();
  163. }
  164.  
  165. void
  166. output(int x, int y, char *string)
  167. {
  168.   int len, i;
  169.  
  170.   glRasterPos2f(x, y);
  171.   len = (int) strlen(string);
  172.   for (i = 0; i < len; i++) {
  173.     glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, string[i]);
  174.   }
  175. }
  176.  
  177. char *helpMsg[] =
  178. {
  179.   "Welcome to zoomdino!",
  180.   "   Left mouse button rotates",
  181.   "     the dinosaur.",
  182.   "   Middle mouse button zooms",
  183.   "     via overlay rubber-banding.",
  184.   "   Right mouse button shows",
  185.   "     pop-up menu.",
  186.   "   To reset view, use \"Reset",
  187.   "     Projection\".",
  188.   "(This message is in the overlays.)",
  189.   NULL
  190. };
  191.  
  192. void
  193. redrawOverlay(void)
  194. {
  195.   if (help) {
  196.     int i;
  197.  
  198.     glClear(GL_COLOR_BUFFER_BIT);
  199.     glIndexi(white);
  200.     for (i = 0; helpMsg[i]; i++) {
  201.       output(15, 24 + i * 18, helpMsg[i]);
  202.     }
  203.     return;
  204.   }
  205.   if (glutLayerGet(GLUT_OVERLAY_DAMAGED) || clearHelp) {
  206.     /* Opps, damage means we need a full clear. */
  207.     glClear(GL_COLOR_BUFFER_BIT);
  208.     clearHelp = 0;
  209.     wasFancy = 0;
  210.   } else {
  211.     /* Goody!  No damage.  Just erase last rubber-band. */
  212.     if (fancy || wasFancy) {
  213.       glLineWidth(3.0);
  214.     }
  215.     glIndexi(transparent);
  216.     glBegin(GL_LINE_LOOP);
  217.     glVertex2i(anchorx, anchory);
  218.     glVertex2i(anchorx, pstretchy);
  219.     glVertex2i(pstretchx, pstretchy);
  220.     glVertex2i(pstretchx, anchory);
  221.     glEnd();
  222.   }
  223.   if (wasFancy) {
  224.     glLineWidth(1.0);
  225.     wasFancy = 0;
  226.   }
  227.   if (fancy)
  228.     glLineWidth(3.0);
  229.   glIndexi(red);
  230.   glBegin(GL_LINE_LOOP);
  231.   glVertex2i(anchorx, anchory);
  232.   glVertex2i(anchorx, stretchy);
  233.   glVertex2i(stretchx, stretchy);
  234.   glVertex2i(stretchx, anchory);
  235.   glEnd();
  236.   if (fancy) {
  237.     glLineWidth(1.0);
  238.     glIndexi(white);
  239.     glBegin(GL_LINE_LOOP);
  240.     glVertex2i(anchorx, anchory);
  241.     glVertex2i(anchorx, stretchy);
  242.     glVertex2i(stretchx, stretchy);
  243.     glVertex2i(stretchx, anchory);
  244.     glEnd();
  245.   }
  246.   glFlush();
  247.  
  248.   /* Remember last place rubber-banded so the rubber-band can
  249.      be erased next redisplay. */
  250.   pstretchx = stretchx;
  251.   pstretchy = stretchy;
  252. }
  253.  
  254. void
  255. defaultProjection(void)
  256. {
  257.   glMatrixMode(GL_PROJECTION);
  258.   glLoadIdentity();
  259.   vx = -1.0;
  260.   vw = 2.0;
  261.   vy = -1.0;
  262.   vh = 2.0;
  263.   glFrustum(vx, vx + vw, vy, vy + vh, 1.0, 40);
  264.   glMatrixMode(GL_MODELVIEW);
  265. }
  266.  
  267. void
  268. mouse(int button, int state, int x, int y)
  269. {
  270.   if (button == GLUT_LEFT_BUTTON) {
  271.     if (state == GLUT_DOWN) {
  272.       glutSetCursor(GLUT_CURSOR_LEFT_RIGHT);
  273.       moving = 1;
  274.       begin = x;
  275.     } else if (state == GLUT_UP) {
  276.       glutSetCursor(GLUT_CURSOR_INHERIT);
  277.       moving = 0;
  278.     }
  279.   }
  280.   if (overlaySupport && button == GLUT_MIDDLE_BUTTON) {
  281.     if (state == GLUT_DOWN) {
  282.       help = 0;
  283.       clearHelp = 1;
  284.       rubberbanding = 1;
  285.       anchorx = x;
  286.       anchory = y;
  287.       stretchx = x;
  288.       stretchy = y;
  289.       glutShowOverlay();
  290.     } else if (state == GLUT_UP) {
  291.       rubberbanding = 0;
  292.       glutHideOverlay();
  293.       glutUseLayer(GLUT_NORMAL);
  294.       glMatrixMode(GL_PROJECTION);
  295.       glLoadIdentity();
  296.  
  297. #undef max
  298. #undef min
  299. #define max(a,b)  ((a) > (b) ? (a) : (b))
  300. #define min(a,b)  ((a) < (b) ? (a) : (b))
  301.  
  302.       wx = min(anchorx, stretchx);
  303.       wy = min(H - anchory, H - stretchy);
  304.       wx2 = max(anchorx, stretchx);
  305.       wy2 = max(H - anchory, H - stretchy);
  306.       ww = wx2 - wx;
  307.       wh = wy2 - wy;
  308.       if (ww == 0 || wh == 0) {
  309.         glutUseLayer(GLUT_NORMAL);
  310.         defaultProjection();
  311.       } else {
  312.  
  313.         vx2 = wx2 / W * vw + vx;
  314.         vx = wx / W * vw + vx;
  315.         vy2 = wy2 / H * vh + vy;
  316.         vy = wy / H * vh + vy;
  317.         vw = vx2 - vx;
  318.         vh = vy2 - vy;
  319.  
  320.         glFrustum(vx, vx + vw, vy, vy + vh, 1.0, 40);
  321.       }
  322.       glutPostRedisplay();
  323.       glMatrixMode(GL_MODELVIEW);
  324.     }
  325.   }
  326. }
  327.  
  328. void
  329. motion(int x, int y)
  330. {
  331.   if (moving) {
  332.     angle = angle + (x - begin);
  333.     begin = x;
  334.     newModel = 1;
  335.     glutPostRedisplay();
  336.   }
  337.   if (rubberbanding) {
  338.     stretchx = x;
  339.     stretchy = y;
  340.     glutPostOverlayRedisplay();
  341.   }
  342. }
  343.  
  344. void
  345. reshape(int w, int h)
  346. {
  347.   if (overlaySupport) {
  348.     glutUseLayer(GLUT_OVERLAY);
  349.     glViewport(0, 0, w, h);
  350.     glMatrixMode(GL_PROJECTION);
  351.     glLoadIdentity();
  352.     gluOrtho2D(0, w, 0, h);
  353.     glScalef(1, -1, 1);
  354.     glTranslatef(0, -h, 0);
  355.     glMatrixMode(GL_MODELVIEW);
  356.     glutUseLayer(GLUT_NORMAL);
  357.   }
  358.   glViewport(0, 0, w, h);
  359.   W = w;
  360.   H = h;
  361. }
  362.  
  363. GLboolean lightZeroSwitch = GL_TRUE, lightOneSwitch = GL_TRUE;
  364.  
  365. void
  366. controlLights(int value)
  367. {
  368.   glutUseLayer(GLUT_NORMAL);
  369.   switch (value) {
  370.   case 1:
  371.     lightZeroSwitch = !lightZeroSwitch;
  372.     if (lightZeroSwitch) {
  373.       glEnable(GL_LIGHT0);
  374.     } else {
  375.       glDisable(GL_LIGHT0);
  376.     }
  377.     break;
  378.   case 2:
  379.     lightOneSwitch = !lightOneSwitch;
  380.     if (lightOneSwitch) {
  381.       glEnable(GL_LIGHT1);
  382.     } else {
  383.       glDisable(GL_LIGHT1);
  384.     }
  385.     break;
  386.   case 3:
  387.     defaultProjection();
  388.     break;
  389.   case 4:
  390.     fancy = 1;
  391.     break;
  392.   case 5:
  393.     fancy = 0;
  394.     wasFancy = 1;
  395.     break;
  396.   case 6:
  397.     if (!rubberbanding)
  398.       help = 1;
  399.     glutShowOverlay();
  400.     glutPostOverlayRedisplay();
  401.     break;
  402.   }
  403.   glutPostRedisplay();
  404. }
  405.  
  406. int
  407. main(int argc, char **argv)
  408. {
  409.   glutInit(&argc, argv);
  410.   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
  411.   glutCreateWindow("zoomdino");
  412.   glutDisplayFunc(redraw);
  413.   glutMouseFunc(mouse);
  414.   glutMotionFunc(motion);
  415.   glutCreateMenu(controlLights);
  416.   glutAddMenuEntry("Toggle right light", 1);
  417.   glutAddMenuEntry("Toggle left light", 2);
  418.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  419.   makeDinosaur();
  420.   glEnable(GL_CULL_FACE);
  421.   glEnable(GL_DEPTH_TEST);
  422.   glEnable(GL_LIGHTING);
  423.   defaultProjection();
  424.   gluLookAt(0.0, 0.0, 30.0,  /* eye is at (0,0,30) */
  425.     0.0, 0.0, 0.0,      /* center is at (0,0,0) */
  426.     0.0, 1.0, 0.);      /* up is in postivie Y direction */
  427.   glPushMatrix();       /* dummy push so we can pop on model
  428.                            recalc */
  429.   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
  430.   glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);
  431.   glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
  432.   glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
  433.   glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
  434.   glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition);
  435.   glLightfv(GL_LIGHT1, GL_DIFFUSE, lightOneColor);
  436.   glEnable(GL_LIGHT0);
  437.   glEnable(GL_LIGHT1);
  438.   glutInitDisplayMode(GLUT_SINGLE | GLUT_INDEX);
  439.   overlaySupport = glutLayerGet(GLUT_OVERLAY_POSSIBLE);
  440.   if (overlaySupport) {
  441.     glutEstablishOverlay();
  442.     glutHideOverlay();
  443.     transparent = glutLayerGet(GLUT_TRANSPARENT_INDEX);
  444.     glClearIndex(transparent);
  445.     red = (transparent + 1) % glutGet(GLUT_WINDOW_COLORMAP_SIZE);
  446.     white = (transparent + 2) % glutGet(GLUT_WINDOW_COLORMAP_SIZE);
  447.     glutSetColor(red, 1.0, 0.0, 0.0);  /* Red. */
  448.     glutSetColor(white, 1.0, 1.0, 1.0);  /* White. */
  449.     glutOverlayDisplayFunc(redrawOverlay);
  450.     glutReshapeFunc(reshape);
  451.     glutSetWindowTitle("zoomdino with rubber-banding");
  452.     glutAddMenuEntry("------------------", 0);
  453.     glutAddMenuEntry("Reset projection", 3);
  454.     glutAddMenuEntry("------------------", 0);
  455.     glutAddMenuEntry("Fancy rubber-banding", 4);
  456.     glutAddMenuEntry("Simple rubber-banding", 5);
  457.     glutAddMenuEntry("------------------", 0);
  458.     glutAddMenuEntry("Show help", 6);
  459.   } else {
  460.     printf("Sorry, no whizzy zoomdino overlay usage!\n");
  461.   }
  462.   glutMainLoop();
  463.   return 0;             /* ANSI C requires main to return int. */
  464. }
  465.